package com.mall.ware.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.mall.common.dto.OrderLockItemDTO;
import com.mall.common.dto.SkuInfoDTO;
import com.mall.common.dto.WareOrderTaskDetailDTO;
import com.mall.common.page.PageData;
import com.mall.common.service.impl.CrudServiceImpl;
import com.mall.common.utils.ConvertUtils;
import com.mall.common.utils.ParamUtils;
import com.mall.common.utils.Result;
import com.mall.ware.dao.WareSkuDao;
import com.mall.ware.dto.WareSkuDTO;
import com.mall.ware.dto.WareSkuLockDto;
import com.mall.ware.entity.WareOrderTaskDetailEntity;
import com.mall.ware.entity.WareOrderTaskEntity;
import com.mall.ware.entity.WareSkuEntity;
import com.mall.ware.service.WareOrderTaskDetailService;
import com.mall.ware.service.WareOrderTaskService;
import com.mall.ware.service.WareSkuService;
import com.mall.ware.feign.ProductFeignClient;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 商品库存
 *
 * @author xjc xjc@163.com
 * @since 1.0.0 2022-07-17
 */
@Slf4j
@Service
public class WareSkuServiceImpl extends CrudServiceImpl<WareSkuDao, WareSkuEntity, WareSkuDTO> implements WareSkuService {

    @Resource
    private WareSkuDao wareSkuDao;
    @Resource
    private ProductFeignClient productFeignClient;
    @Resource
    private WareOrderTaskService wareOrderTaskService;
    @Resource
    private WareOrderTaskDetailService wareOrderTaskDetailService;
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Override
    public QueryWrapper<WareSkuEntity> getWrapper(Map<String, Object> params) {
        String id = (String) params.get("id");

        QueryWrapper<WareSkuEntity> wrapper = new QueryWrapper<>();
        wrapper.eq(StringUtils.isNotBlank(id), "id", id);

        return wrapper;
    }


    @Override
    public PageData<WareSkuDTO> queryPageByCondition(Map<String, Object> params) {
        Long skuId = ParamUtils.strParseLong(params.get("skuId"));
        Long wareId = ParamUtils.strParseLong(params.get("wareId"));
        QueryWrapper<WareSkuEntity> wrapper = new QueryWrapper<>();
        wrapper.eq(skuId > 0, "sku_id", skuId);
        wrapper.eq(wareId > 0, "ware_id", wareId);
        IPage<WareSkuEntity> selectPage = baseDao.selectPage(getPage(params, null, false), wrapper);
        return new PageData<>(ConvertUtils.sourceToTarget(selectPage.getRecords(), WareSkuDTO.class), selectPage.getTotal());
    }

    @Override
    public void addStock(Long skuId, Long wareId, Integer skuNum) {

        Long count = baseDao.selectCount(new QueryWrapper<WareSkuEntity>().eq("sku_id", skuId).eq("ware_id", wareId));
        if (count == null || count == 0) {
            // 没有新增
            WareSkuEntity wareSku = new WareSkuEntity();
            wareSku.setSkuId(skuId);
            wareSku.setWareId(wareId);
            // 远程获取produceName
            // todo 异常其他处理方式
            try {
                Result<SkuInfoDTO> result = productFeignClient.getInfo(skuId);
                wareSku.setSkuName(result.getData().getSkuName());
            } catch (Exception e) {
                log.error("feign远程调用异常，异常:"+e.getMessage());
            }
            wareSku.setStock(0);
            wareSku.setStock(skuNum);
            baseDao.insert(wareSku);
        } else {
            //更新
            wareSkuDao.addStock(skuId, wareId, skuNum);
        }
    }

    @Override
    public List<Long> hasStock(List<Long> skuIds) {
        List<WareSkuEntity> stock = baseDao.getStock(skuIds);
        if (stock==null||stock.size()<=0)
            return new ArrayList<>();
        List<Long> collect = stock.stream().filter(item -> item.getStock() > 0).map(WareSkuEntity::getSkuId).collect(Collectors.toList());
        return collect;
    }

    /**
     *
     * @param  dto
     * @throws RuntimeException
     * 库存解锁场景：
     *     1.订单回滚解锁
     *     2.订单到期未支付解锁
     *     3.用户手动取消订单
     */

    @Transactional
    @Override
    public void orderLockStock(WareSkuLockDto dto) throws RuntimeException {
        WareOrderTaskEntity taskEntity = new WareOrderTaskEntity();
        taskEntity.setOrderSn(dto.getOrderSn());
        wareOrderTaskService.insert(taskEntity);

        List<OrderLockItemDTO> locks = dto.getLocks();
        List<SkuWareHasStock> stockList = locks.stream().map(item -> {
            SkuWareHasStock skuWareHasStock = new SkuWareHasStock();
            Long skuId = item.getSkuId();
            skuWareHasStock.setSkuId(skuId);
            skuWareHasStock.setSkuName(item.getSkuName());
            skuWareHasStock.setNum(item.getSkuQuantity());
            List<Long> wareIds = wareSkuDao.ListWareIdWithStock(skuId);
            skuWareHasStock.setWareIds(wareIds);
            return skuWareHasStock;
        }).collect(Collectors.toList());
        // 锁定库存
        for (SkuWareHasStock stock : stockList) {
            boolean currenLock = true;
            Long skuId = stock.getSkuId();
            List<Long> wareIds = stock.getWareIds();
            if (wareIds==null || wareIds.size()<=0)
                throw new RuntimeException("库存不足");
            for (Long wareId : wareIds) {
                Long lockFlag = wareSkuDao.lockStock(skuId, wareId, stock.getNum());
                if (lockFlag != 1L){
                    currenLock = false;
                }else {
                    // 锁定成功
                    WareOrderTaskDetailEntity taskDetail = new WareOrderTaskDetailEntity();
                    taskDetail.setSkuName(stock.getSkuName());
                    taskDetail.setSkuId(skuId);
                    taskDetail.setLockStatus(1L);
                    taskDetail.setSkuNum(stock.getNum());
                    taskDetail.setTaskId(taskEntity.getId());
                    taskDetail.setWareId(wareId);
                    wareOrderTaskDetailService.insert(taskDetail);
                    WareOrderTaskDetailDTO taskDetailDTO = ConvertUtils.sourceToTarget(taskDetail, WareOrderTaskDetailDTO.class);
                    taskDetailDTO.setOrderSn(taskEntity.getOrderSn());
                    rabbitTemplate.convertAndSend(
                            "stock-event-exchange",
                            "stock.locked",
                            taskDetailDTO);
                    currenLock = true;
                    break;
                }
            }
            if (!currenLock)
                throw new RuntimeException("商品：" + skuId + "锁定库存失败！");
        }
    }

    @Transactional
    @Override
    public void unLockStock(Long id,Long skuId, Long wareId, Integer skuNum) {
        baseDao.unLockStock(skuId,wareId,skuNum);
        WareOrderTaskDetailEntity taskDetail = new WareOrderTaskDetailEntity();
        taskDetail.setId(id);
        taskDetail.setLockStatus(2L);
        wareOrderTaskDetailService.updateById(taskDetail);
    }

    @Override
    public void reduceStock(Long wareId, Long skuId, Integer skuNum) {
        Long updateItems = baseDao.reduceStock(wareId, skuId, skuNum);
        log.info("减库存：" + updateItems);
    }

    @Data
    public class SkuWareHasStock{
        private Long skuId;
        private String skuName;
        private List<Long> wareIds;
        private Integer num;
    }
}